using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reactive.Linq;
using System.Threading.Tasks;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Notifications;
using Avalonia.Interactivity;
using Avalonia.Platform.Storage;
using Avalonia.ReactiveUI;
using DynamicData;
using LiteDB;
using PackagingTool.Helpers;
using PackagingTool.Models;
using PackagingTool.ViewModels;
using ReactiveUI;

namespace PackagingTool.Views;

public partial class MainWindow : ReactiveWindow<MainWindowViewModel>
{
    private WindowNotificationManager? _manager;
    private static readonly List<SelectFileItem> SelectFile = new();

    public MainWindow()
    {
        InitializeComponent();
        this.WhenActivated(action =>
            action(ViewModel!.ShowDialog.RegisterHandler(DoShowDialogAsync)));

        this.WhenActivated(action =>
            action(ViewModel!.ShowBuildPlanDialog.RegisterHandler(DoShowBuildPlanAsync)));
    }

    private MainWindowViewModel ViewModel => (MainWindowViewModel)DataContext;


    private async Task DoShowBuildPlanAsync<TValue, TResult>(InteractionContext<TValue, TResult> interaction)
    {
        var dialog = new BuildPlan()
        {
            DataContext = interaction.Input
        };

        var result = await dialog.ShowDialog<TResult>(this);

        interaction.SetOutput(result);
    }

    private async Task DoShowDialogAsync<TValue, TResult>(
        InteractionContext<TValue, TResult> interaction)
    {
        var dialog = new BuildProjectSetting
        {
            DataContext = interaction.Input
        };

        var result = await dialog.ShowDialog<TResult>(this);
        interaction.SetOutput(result);
    }

    protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
    {
        base.OnAttachedToVisualTree(e);
        var topLevel = GetTopLevel(this);
        _manager = new WindowNotificationManager(topLevel) { MaxItems = 3 };
    }

    private async void Button_OnClick(object? sender, RoutedEventArgs e)
    {
        IStorageProvider? sp = GetStorageProvider();
        if (sp is null) return;
        var result = await sp.OpenFolderPickerAsync(new FolderPickerOpenOptions()
        {
            Title = "Select Folder",
            AllowMultiple = true,
        });

        ViewModel.Files.Clear();
        SelectFile.Clear();

        foreach (var folder in result)
        {
            foreach (var file in GetFilesRecursively(folder.Path.AbsolutePath))
            {
                var item = new SelectFileItem()
                {
                    IsSelected = false,
                    Name = Path.GetFileName(file),
                    Size = StringHelper.BytesToString(new FileInfo(file).Length),
                    Path = file
                };
                SelectFile.Add(item);
                ViewModel.Files.Add(item);
            }
        }
    }

    private IStorageProvider? GetStorageProvider()
    {
        var topLevel = GetTopLevel(this);
        return topLevel?.StorageProvider;
    }

    private static IEnumerable<string> GetFilesRecursively(string basePath)
    {
        // Get all files at the base path
        var fileEntries = Directory.GetFiles(basePath);
        foreach (var fileName in fileEntries)
        {
            yield return fileName;
        }

        // Get all directories at the base path
        var subdirectoryEntries = Directory.GetDirectories(basePath);
        foreach (var subdirectory in subdirectoryEntries)
        {
            // Use recursion to explore all subdirectories
            foreach (var fileName in GetFilesRecursively(subdirectory))
            {
                yield return fileName;
            }
        }
    }

    private void SelectMainAssembly_OnClick(object? sender, RoutedEventArgs e)
    {
        if (sender is Button { DataContext: SelectFileItem item })
        {
            if (!item.IsSelected)
            {
                if (ViewModel.Files.Any(x => x.IsSelected))
                {
                    var notification = new Notification("Error", "Only one main assembly can be selected");

                    _manager?.Show(notification);
                    return;
                }

                item.IsSelected = true;
            }
            else
                item.IsSelected = false;
        }
    }

    private void DeleteFile_OnClick(object? sender, RoutedEventArgs e)
    {
        if (sender is Button { DataContext: SelectFileItem item })
        {
            ViewModel.Files.Remove(item);
        }
    }

    private async void BuildProject_OnClick(object? sender, RoutedEventArgs e)
    {
        if (!ViewModel.Files.Any(x => x.IsSelected))
        {
            _manager?.Show(new Notification("Error", "Please select the import assembly", NotificationType.Error));
            return;
        }

        var view = new BuildProjectSettingViewModel();
        var result = await ViewModel.ShowDialog.Handle(view);

        if (result != null)
        {
            // 开始构建
            if (!Directory.Exists(result.ProjectOutputPath))
            {
                _manager?.Show(new Notification("Error", "Directory does not exist", NotificationType.Error));
                return;
            }

            var planView = new BuildPlanViewModel()
            {
                ProgressValue = 0,
                SelectFileItems = ViewModel.Files,
                Path = Path.Combine(result.ProjectOutputPath, result.ProjectName)
            };

            if (sender is not Button but)
                return;

            but.IsEnabled = false;

            try
            {
                var buildResult = await ViewModel.ShowBuildPlanDialog.Handle(planView);
            }
            finally
            {
                but.IsEnabled = true;
            }
        }
    }

    private void Search_OnClick(object? sender, RoutedEventArgs e)
    {
        ViewModel.Files.Clear();
        if (string.IsNullOrEmpty(ViewModel.Search))
        {
            ViewModel.Files.AddRange(SelectFile);
            return;
        }

        ViewModel.Files.AddRange(SelectFile.Where(x => x.Name.ToLower().Contains(ViewModel.Search.ToLower())));
    }
}